
package com.feib.ebilling.job;

import java.io.BufferedReader;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.FileReader;
import java.io.IOException;
import java.text.SimpleDateFormat;
import java.util.Calendar;
import java.util.Date;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Properties;

import javax.annotation.Resource;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import org.springframework.stereotype.Service;

import com.feib.ebilling.job.service.BankingFeedbackService;
import com.feib.ebilling.job.service.FtpService;
import com.feib.ebilling.job.service.MqService;
import com.feib.ebilling.job.util.SortedProperties;
import com.feib.ebilling.job.util.StringUtils;


/**
 * @title (#)BankingFeedbackService.java<br>
 * @description 銀行代收通路銷帳批次回饋，日曆日出銷帳檔<br>
 * @author Jimmy Liu<br>
 * @version 1.0.0 2010/11/25
 * @copyright Far Eastern International Bank Copyright (c) 2010<br>
 * @2010/12/10 create by Jimmy Liu<br>
 */
@Service("bankingFeedback")
public class BankingFeedback {

    public static Logger logger = LoggerFactory.getLogger(BankingFeedback.class);

    public static final SimpleDateFormat BASIC_DATE_TIME_FORMAT = new SimpleDateFormat("yyyy/MM/dd HH:mm:ss");
    
    private static ApplicationContext ctx = null;

    @Resource(name="bankingFeedbackService")
    private BankingFeedbackService bankingFeedbackService;

    @Resource(name="ftpService")
    private FtpService ftpService;

    @Resource(name="batchProperties")
    private Properties batchProperties;

    @Resource(name="taskProperties")
    private Properties taskPropertiesBean;
    
    private SortedProperties taskProperties;

    @Resource(name="taskPropertiesSaveTo")
    private String taskPropertiesSaveTo;


    /**
     * 銀行代收通路銷帳批次回饋
     * @param args array, args[0]民國日期  args[1]24時間起 args[2]24時間迄<br>
     * 不輸入，抓系統時間處理
     */
    public static void main(String[] args) {

        BankingFeedback.ctx = new ClassPathXmlApplicationContext(
                        new String[] {"applicationContext-config.xml", "applicationContext-dao.xml", "applicationContext-properties.xml"});

        Date start = new Date();
        logger.info("[開始] 銀行代收通路銷帳批次回饋  - {}", BASIC_DATE_TIME_FORMAT.format(start));
        try {
            BankingFeedback bankingFeedback = (BankingFeedback)BankingFeedback.ctx.getBean("bankingFeedback");
            
            if (args.length==0){
                bankingFeedback.execute();
            }
            else
            {
                /* 執行指定日期、時間檔案 */      
                logger.info("傳入銷帳參數：" + args[0] + "," + args[1] + "-" + args[2]);
                if (bankingFeedback.doFeedBack(args[0], args[1], args[2])){
                    logger.info("銷帳成功：" + args[0] + "," + args[1] + "-" + args[2]);
                }else{
                    logger.info("銷帳失敗：" + args[0] + "," + args[1] + "-" + args[2]);
                }
            }

        }
        catch (Exception e) {
            logger.error(e.getMessage(), e);
        }
        finally{
            Date end = new Date();
            logger.info("[結束] 銀行代收通路銷帳批次回饋  - ", BASIC_DATE_TIME_FORMAT.format(end));
            logger.info("共費時 - " + ((end.getTime() - start.getTime()) / 1000) + " 秒");
        }

    }
    
    protected Properties getTaskProperties()
    {
        if (null == taskProperties)
        {
            taskProperties = new SortedProperties();
            Iterator<Object> it = this.taskPropertiesBean.keySet().iterator();
            while(it.hasNext())
            {
               String key = (String)it.next();
               taskProperties.put(key, this.taskPropertiesBean.getProperty(key));
            }
        }
        
        return taskProperties;
    }
    
    /**
     * Main中不輸入參數時執行，抓取工作日期與時間
     * @throws FileNotFoundException
     * @throws IOException
     */
    public void execute() throws FileNotFoundException, IOException
    {
        /* 系統日期 */
        String sSystemDate = StringUtils.PadString("R", "0", 7, StringUtils.GetStrCDate());
        /* 系統時間 */
        String sSystemTime = null;
                                    
        /* 一天有幾次要Feed Back */
        int iTask = Integer.parseInt(getTaskProperties().getProperty("Task"));
        logger.info("Task Count：{}", iTask);                       
        if (sSystemDate.equals(getTaskProperties().getProperty("SystemDate"))){
            Calendar cal = Calendar.getInstance();
            //cal.set(Calendar.MINUTE, -30); // 做半小時前的task，例如，現在是 11:20 分，那麼就是做 10:50 分那一個task
            sSystemTime = new SimpleDateFormat("HHmmss").format(cal.getTime());
            sSystemTime = sSystemTime + "99";
        }else{
            /* 換日要把上一次未做的做完 */   
            sSystemTime = "23595999";
            logger.info("換日，要把昨日未做的做完");
        }
        logger.info("銷帳系統日期：{}", sSystemDate);
        logger.info("銷帳系統時間：{}", sSystemTime);
        
        for(int i=1; i<=iTask; i++){
            /* 讀取排程設定檔 */                           
            String sTaskNum = "Task" + StringUtils.PadString("R", "0", 3, String.valueOf(i));
            String sTask = getTaskProperties().getProperty(sTaskNum);
            logger.info(sTaskNum + " = " + sTask);
            String[] aTask = sTask.split(",");                              
            /* 需要執行的 */
            if (Integer.parseInt(aTask[1]) <= Integer.parseInt(sSystemTime) &&
                            aTask[2].trim().equals("schedule")){
                getTaskProperties().setProperty(sTaskNum, aTask[0] + "," + aTask[1] + ",process");
                /* 立即寫入檔案，怕重覆執行 */
                getTaskProperties().store(new FileOutputStream(taskPropertiesSaveTo + "task.properties"), null);
                logger.info(sTaskNum + " = " + aTask[0] + "," + aTask[1] + ",process");
                if (sSystemDate.equals(getTaskProperties().getProperty("SystemDate"))){                            
                    /* 系統未換日、系統日回饋處理 */                                             
                    if (doFeedBack(sSystemDate, aTask[0],aTask[1])){
                        getTaskProperties().setProperty(sTaskNum, aTask[0] + "," + aTask[1] + ",success");                                                 
                        logger.info(sTaskNum + " = " + aTask[0] + "," + aTask[1] + ",success");
                    }else{
                        getTaskProperties().setProperty(sTaskNum, aTask[0] + "," + aTask[1] + ",fail");
                        logger.error(sTaskNum + " = " + aTask[0] + "," + aTask[1] + ",fail");
                    }
                }else{
                    /* 系統換日、前一日的資料回饋處理 */
                    if (doFeedBack(getTaskProperties().getProperty("SystemDate"), aTask[0],aTask[1])){
                        getTaskProperties().setProperty(sTaskNum, aTask[0] + "," + aTask[1] + ",success");
                        logger.info(sTaskNum + " = " + aTask[0] + "," + aTask[1] + ",success");
                    }else{
                        getTaskProperties().setProperty(sTaskNum, aTask[0] + "," + aTask[1] + ",fail");                                                    
                        logger.error(sTaskNum + " = " + aTask[0] + "," + aTask[1] + ",fail");
                    }
                }                                       
            }                               
        }
        
        if (!sSystemDate.equals(getTaskProperties().getProperty("SystemDate"))){   
            /* 換日要 Reset所有回饋檔案狀態 */
            for(int i=1; i<=iTask; i++ ){
                String sTaskNum = "Task" + StringUtils.PadString("R", "0", 3, String.valueOf(i));
                String sTask = getTaskProperties().getProperty(sTaskNum);
                String[] aTask = sTask.split(","); 
                sTask = aTask[0] + "," + aTask[1] + "," + "schedule";
                getTaskProperties().setProperty(sTaskNum, sTask);                                  
            }
        }
        /* 回寫系統日期 */
        getTaskProperties().setProperty("SystemDate", sSystemDate); 
        
        getTaskProperties().store(new FileOutputStream(taskPropertiesSaveTo + "task.properties"), null);
        logger.info("更新系統日期：" + sSystemDate );
    }


    /**
     * 取得檔案並新增至虛擬帳號銷帳日誌
     * @param sSystemDate 日期
     * @param sSystemTime_Begin 時間區間起
     * @param sSystemTime_End 時間區間迄
     * @return 成功(True)或是敗(False)
     */
    public boolean doFeedBack(String sSystemDate, String sSystemTime_Begin, String sSystemTime_End){
        try{

            /* 取得資料庫所有「虛擬帳號」對映之「實體帳號」 */
            HashMap<String, Integer> hmAccount = new HashMap<String, Integer>();
            List<Map<String, Object>> rds = bankingFeedbackService.getRealAccounts();
            for(Map<String, Object> rd: rds)
            {
                String sAcctID = ((String)rd.get("ACCOUNT_NO")).trim();
                if (! hmAccount.containsKey(sAcctID)){
                    hmAccount.put(sAcctID, new Integer(1));
                    logger.info("「{}」 虛擬帳號入帳實體帳號：{}", ((String)rd.get("GROUP_NAME")),  sAcctID);
                }
            }

            boolean bRtn = true;
            String cnt = "";

            /* 執行送優利電文  */
            if (sendRequest(sSystemDate, sSystemTime_Begin, sSystemTime_End)){
                
                String waitForFtpFileProperty = batchProperties.getProperty("WaitForFtpFile");
                String localFolderProperty = batchProperties.getProperty("LocalFolder");

                logger.info("Wait for File {} ms", waitForFtpFileProperty); 
                /* 等優利產生檔案 */
                Thread.sleep(Long.parseLong(waitForFtpFileProperty));

                /* FTP 取得銷帳筆數檔 */
                String sFileName = "VC_" + sSystemDate + "_" + sSystemTime_Begin + "_" + sSystemTime_End + "_CNT.TXT";
                
                if (ftpService.retryGetFtpFile("FEIB", sFileName)){
                    /* 檢核檔案是否已產生  */                                
                    File ftpFile = new File(localFolderProperty + "\\" + sFileName);
                    if(ftpFile.exists()){
                        logger.info("Read file : {}", ftpFile.getAbsolutePath());
                        
                        BufferedReader in = new BufferedReader(new FileReader(ftpFile));
                        String str = null;                                                               
                        while ((str = in.readLine()) != null) {
                            /* 檔案總筆數 */ 
                            cnt = str.substring(0,8).trim();                                      
                        }                        
                    }else{
                        /* 無下載檔案資料 */        
                        logger.error("[錯誤]Open {} failed.", sFileName);
                        bRtn = false;
                    }
                }else{
                    /* FTP 取檔失敗 */       
                    logger.error("[錯誤]Get Ftp file {} failed", sFileName);
                    bRtn = false; 
                }

                /* FTP 取得銷帳明細檔 */
                sFileName = "VC_" + sSystemDate + "_" + sSystemTime_Begin + "_" + sSystemTime_End + ".TXT";
                
                // 檢核是否已經有檔名相同且已處理過了
                if (this.bankingFeedbackService.hasWriteoff(sFileName))
                {
                    logger.error("[錯誤]檔名 {} 於資料表FEEDBACK_LOG 中已有銷帳成功紀錄.", sFileName);
                    bRtn = false; 
                }
                else
                {
                    logger.info("刪除銀行代收通路銷帳日誌, 檔名 {}", sFileName);
                    this.bankingFeedbackService.removeBankFeedbackLog(sFileName);
                }
                

                /* 如果第一個檔案下載失敗，第二個檔案就不下載了。 */
                if (bRtn == true && !"00000000".equals(cnt) &&
                                ftpService.retryGetFtpFile("FEIB", sFileName) ){
                    /* 檢核檔案是否已銷帳  */
                    File ftpFile = new File(localFolderProperty + "\\" + sFileName);
                    if(ftpFile.exists()){
                        logger.info("Read file : {}", ftpFile.getAbsolutePath());
                        BufferedReader in = new BufferedReader(new FileReader(ftpFile));
                        String str = null;                               
                        long  totalcount = 0;
                        long  realcount = 0;
                        while ((str = in.readLine()) != null) {
                            totalcount++;
                            String[] sData = new String[19]; 
                            /* 實體帳號 */                                              
                            sData[0] = str.substring(0,14).trim();                                          
                            if (hmAccount.get(sData[0]) == null){
                                /* 系統無實體帳號要入帳，跳過該筆資料不檢核 */                                              
                                continue;
                            }                                                                       
                            /* 交易日 */
                            sData[1] = str.substring(14,22); // 這裡是民國年
                            sData[1] = String.valueOf(Integer.parseInt(sData[1])+19110000); // 轉為西元年月日
                            /* 交易時間 */
                            sData[2] = str.substring(22,30); // HHMMSShh
                            /* 營業日 */
                            sData[3] = str.substring(30,38); // 這裡是民國年
                            sData[3] = String.valueOf(Integer.parseInt(sData[3])+19110000); // 轉為西元年月日
                            /* 交易種類(自動化為0) */
                            sData[4] = str.substring(38,39);
                            /* 交易代號(自動化為空白) */
                            sData[5] = str.substring(39,41);
                            /* 摘要(037為匯款), 自動化為 1 */
                            sData[6] = str.substring(41,44);
                            /* 交易金額 */
                            sData[7] = str.substring(44,55);
                            /* 虛擬帳號  */
                            sData[8] = str.substring(55,71);
                            if (sData[8].length() == 16 && sData[8].substring(0,2).equals("00")){
                            	/* 虛擬帳號應為14碼  */
                            	sData[8] = sData[8].substring(2,16);
                            }else{
                            	sData[8] = sData[8].trim();
                            }                                         
                            /* ATM機號  */
                            sData[9] = str.substring(71,79);
                            /* 交易行  (891為跨行)*/
                            sData[10] = str.substring(79,82);
                            /* 工作站代號  */
                            sData[11] = str.substring(82,84);
                            /* 交易序號 */
                            sData[12] = str.substring(84,89);
                            /* 轉帳銀行 */
                            sData[13] = str.substring(89,92);
                            /* 轉帳帳號 */
                            sData[14] = str.substring(92,108);
                            /* 財金交易代理行 */
                            sData[15] = str.substring(108,111);
                            /* 財金交易序號 */
                            sData[16] = str.substring(111,118);
                            /* 沖正記號 (0正常、1沖正) */
                            sData[17] = str.substring(118,119);
                            /* 通路別(0:臨櫃,1:網銀,2:ATM,3:中心轉帳BIO) */
                            sData[18] = str.substring(119,120);
                            
                            /* 新增至銀行繳款通路銷帳日誌 */                            
                            this.bankingFeedbackService.addBankFeedbackLog(sData, sFileName);
                            realcount++;
                        }                                       
                        if (totalcount != Long.parseLong(cnt)){
                            logger.error("[錯誤]虛擬帳號銷帳檔案筆數不合： " + cnt + "，請人工檢核...");
                            /* 刪除已寫入銀行繳款通路銷帳日誌 */                                                  
                            logger.info("Delete FeeBack Data:" + sFileName);
                            this.bankingFeedbackService.removeBankFeedbackLog(sFileName);                            
                            return false;
                        }else{
                            logger.info("虛擬帳號銷帳檔案筆數： {}", cnt);
                            logger.info("實際符合銷帳檔案筆數： {}", StringUtils.PadString("R", "0", 8, String.valueOf(realcount)));
                            
                            doWriteOff(sFileName);
                        }
                    }else{                             
                        /* Local 讀檔失敗 */
                        logger.error("[錯誤]Open failed.", sFileName);
                        bRtn = false;
                    }
                }else{                                       
                    if ("00000000".equals(cnt)){
                        logger.info("無銷帳資料可回饋");
                        bRtn = true;
                    }else{
                        /* FTP 取檔失敗 */
                        logger.error("[錯誤]Get Ftp file {} failed.", sFileName);
                        bRtn = false;
                    }
                }    
            }else{
                /* MQ 送電文失敗 */   
                logger.error("[錯誤]送優利MQ電文failed ");
                bRtn = false; 
            }
            return bRtn;
        }catch (Exception ex){
            logger.error("[錯誤]" + ex.toString(), ex);
            return false;
        }
    }
    
    public boolean sendRequest(String sDate,String sTimeBegin, String sTimeEnd)
    {
        try
        {

            MqService mqService = (MqService)ctx.getBean("mqService"); 

            /* 遠銀虛擬帳號入帳明細查詢電文 --> 通知優利產生檔案 */
            logger.info("SendMQ starting...");
            String cdate = StringUtils.GetStrCDate();
            if (cdate.length() > 6)
                cdate = cdate.substring(1, 7);                
            String myTITA = "  " + mqService.getMyTITA().substring(0,3) + cdate + mqService.getMyTITA().substring(9, mqService.getMyTITA().length());

            /* 交易日 */
            myTITA += sDate;
            /* 交易時間起點(含) */
            myTITA += sTimeBegin;
            /* 交易時間終點(含) */
            myTITA += sTimeEnd;              

            mqService.setMyTITA(myTITA);

            if ("1".equals(MqService.MQonline))  {
                /* MQ Online */ 
                mqService.send(myTITA, MqService.MSG_TYPE_NONEXML, mqService.getMyMessageID(), "");
            }else{  
                /* Fake MQ 模擬電文 */
                mqService.send(myTITA, MqService.MSG_TYPE_NONEXML, mqService.getMyMessageID(), "TOTA.txt");
            }

            String totaStr = mqService.rcv(mqService.getMyMessageID());

            if (totaStr != null && totaStr.length() >= 19)
                logger.info("SendMQ Result=" + totaStr.substring(15,19));     
            if (totaStr.indexOf("G001") < 0){
                return false;
            }
            return true;
        }
        catch (Exception ex){
            logger.error("[錯誤]"+ex.toString(), ex);
            return false;
        }
    }


    /* 銷帳程式 */
    public void doWriteOff(String sFileName)
    {        
        try{
            this.bankingFeedbackService.writeoffByFile(sFileName);
            
         }catch (Exception ex){
             logger.error("[錯誤]" + ex.toString(), ex);         
         }
    }
}
